package Counter(Counter(..), mkCounter, mkUnsafeCounter) where

--@ XXX THIS PACKAGE NOT DOCUMENTED YET

interface Counter n =
    inc   :: Bit n -> Action
    dec   :: Bit n -> Action
    up    :: Action
    down  :: Action
    value :: Bit n
    setC  :: Bit n -> Action
    setF  :: Bit n -> Action
    clear :: Action

interface VCounter n =
    addA  :: Bit n -> PrimAction
    addB  :: Bit n -> PrimAction
    value :: Bit n
    setC  :: Bit n -> PrimAction
    setF  :: Bit n -> PrimAction

vMkUnsafeCounter :: Bit n -> Module (VCounter n)
vMkUnsafeCounter v =
    module verilog "Counter" (("width",valueOf n), ("init",v)) "CLK" "RST" {
        addA    = "DATA_A" "ADDA";
        addB    = "DATA_B" "ADDB";
        value = "Q_OUT"{reg};
        setC = "DATA_C" "SETC";
        setF = "DATA_F"{reg} "SETF";
    } [ value <> value,
        [addA,addB,setC] <> [addA,addB,setC],
        value <> [addA,addB],  -- a lie!
        [value, addA, addB, setC] < setF,
        value < setC,
        setF << setF
      ]

mkUnsafeCounter :: (IsModule m c) => Bit n -> m (Counter n)
mkUnsafeCounter i = liftModule $
    module
      _v :: VCounter n
      _v <- vMkUnsafeCounter i

      let name = Valid (primGetModuleName _v)
      let t = typeOf (_ :: Bit n)
      primSavePortType name "DATA_A" t
      primSavePortType name "DATA_B" t
      primSavePortType name "Q_OUT" t
      primSavePortType name "DATA_C" t
      primSavePortType name "DATA_F" t

      interface
        inc x = fromPrimAction (_v.addA x)
        dec x = fromPrimAction (_v.addB (negate x))
        up = fromPrimAction (_v.addA 1)
        down = fromPrimAction (_v.addB (negate 1))
        value = _v.value
        setC x = fromPrimAction (_v.setC x)
        setF x = fromPrimAction (_v.setF x)
        clear = fromPrimAction (_v.setF 0)


vMkCounter :: Bit n -> Module (VCounter n)
vMkCounter v =
    module verilog "Counter" (("width",valueOf n), ("init",v)) "CLK" "RST" {
        addA    = "DATA_A" "ADDA";
        addB    = "DATA_B" "ADDB";
        value = "Q_OUT"{reg};
        setC = "DATA_C" "SETC";
        setF = "DATA_F"{reg} "SETF";
    } [ value <> value,
        [addA,addB,setC] <> [addA,addB,setC],
        value < [addA,addB,setC],
        value < setF,
        setF << setF,
        [addA, addB, setC] << setF
      ]

mkCounter :: (IsModule m c) => Bit n -> m (Counter n)
mkCounter i = liftModule $
    module
      _v :: VCounter n
      _v <- vMkCounter i

      let name = Valid (primGetModuleName _v)
      let t = typeOf (_ :: Bit n)
      primSavePortType name "DATA_A" t
      primSavePortType name "DATA_B" t
      primSavePortType name "Q_OUT" t
      primSavePortType name "DATA_C" t
      primSavePortType name "DATA_F" t

      interface
        inc x = fromPrimAction (_v.addA x)
        dec x = fromPrimAction (_v.addB (negate x))
        up = fromPrimAction (_v.addA 1)
        down = fromPrimAction (_v.addB (negate 1))
        value = _v.value
        setC x = fromPrimAction (_v.setC x)
        setF x = fromPrimAction (_v.setF x)
        clear = fromPrimAction (_v.setF 0)
